package com.ilikesoup.instant.monitor.core;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.regex.Pattern;

@FunctionalInterface
public interface MethodNameFilter extends Predicate<Method> {

    @Override
    default boolean test(Method method) {
        return test(method.getName());
    }

    boolean test(String methodName);

    MethodNameFilter WRITE_METHOD_FILTER = methodName -> methodName.startsWith("set");

    static MethodNameFilter startWith(String... prefixes) {
        return new MultiMatcherFilter(String::startsWith, prefixes);
    }

    static MethodNameFilter matches(String regex) {
        return new RegexMethodNameFilter(regex);
    }

    static MethodNameFilter in(String... methodNameList) {
        return new MultiMatcherFilter(Objects::equals, methodNameList);
    }

    class RegexMethodNameFilter implements MethodNameFilter {

        private final Pattern pattern;

        public RegexMethodNameFilter(String regex) {
            this.pattern = Pattern.compile(regex);
        }

        public RegexMethodNameFilter(String regex, int flag) {
            this.pattern = Pattern.compile(regex, flag);
        }

        @Override
        public boolean test(String methodName) {
            return pattern.matcher(methodName).matches();
        }

    }

    class MultiMatcherFilter implements MethodNameFilter {
        private final BiPredicate<String, String> matcher;
        private final String[] matchStrs;

        public MultiMatcherFilter(BiPredicate<String, String> matcher, String... matchStrs) {
            this.matcher = matcher;
            this.matchStrs = matchStrs;
        }

        @Override
        public boolean test(String methodName) {
            for (String matchStr : matchStrs) {
                if(matcher.test(methodName, matchStr)) {
                    return true;
                }
            }
            return false;
        }
    }


}
